package com.ruoyi.faceplus.face;

import com.arcsoft.face.*;
import com.arcsoft.face.enums.ExtractType;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.tool.TimerUtils;
import com.ruoyi.faceplus.constant.FacePlusConstants;
import com.ruoyi.faceplus.domain.FaceConfig;
import com.ruoyi.faceplus.domain.ImageFeature;
import com.ruoyi.faceplus.domain.UserFace;
import com.ruoyi.faceplus.service.IFaceConfigService;
import com.ruoyi.faceplus.service.IUserFaceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;

@Component
public class FaceServer {

    @Value("${arcpro.initQueueSize}")
    private int initQueueSize;

    // 常规识别阀值
    @Value("${arcpro.similarThreshold}")
    private float mSimilarThreshold;

    // 注册人脸识别阀值
    @Value("${arcpro.regSimilarThreshold}")
    private float mRegSimilarThreshold;

    // 戴口罩之别阀值
    @Value("${arcpro.maskSimilarThreshold}")
    private float mMaskSimilarThreshold;

    @Value("${arcpro.imageQuality}")
    private float mImageQuality;

    @Value("${arcpro.maskImageQuality}")
    private float mMaskImageQuality;

    @Value("${arcpro.enableFaceConfig}")
    private Boolean enableFaceConfig;

    @Resource
    private FaceEngineHelper faceEngineHelper;

    @Resource
    private IUserFaceService userFaceService;

    @Resource
    private IFaceConfigService faceConfigService;

    @Autowired
    @Qualifier("redisTemplate")
    public RedisTemplate redisTemplate;

    private final List<UserFace> mFaceRegisterList = new ArrayList<>();

    private final ConcurrentLinkedQueue<FaceEngine> mFaceEngines = new ConcurrentLinkedQueue<>();

    public void init() {
        initEngines(initQueueSize);
        initFaces();
    }

    // 初始化引擎池
    private void initEngines(int mInitTick) {
        if (mFaceEngines.size() >= initQueueSize || mInitTick <= 0) return;
        FaceEngine faceEngine = faceEngineHelper.create();
        if (faceEngine != null) mFaceEngines.offer(faceEngine);
        mInitTick--;
        initEngines(mInitTick);
    }

    // 检测引擎池
    public void checkEngines() {
        System.out.println(TimerUtils.getDateTime() + " ----------------------- 引擎池可使用引擎：" + mFaceEngines.size() + " 人脸数量:" + mFaceRegisterList.size());
        if (mFaceEngines.size() == 0){
            System.out.println("引擎丢失了，重新创建引擎");
            initEngines(initQueueSize);
        }
    }

    // 取出一个引擎
    public FaceEngine faceEnginePoll() {
        if (mFaceEngines.size() > 0) {
            return mFaceEngines.poll();
        }
        return null;
    }

    // 放回一个引擎
    public void faceEngineOffer(FaceEngine mFaceEngine) {
        if (mFaceEngines.size() < initQueueSize) {
            mFaceEngines.offer(mFaceEngine);
        }
    }

    // 初始化人脸队列
    public void initFaces() {
        this.mFaceRegisterList.clear();
        UserFace userFace = new UserFace();
        List<UserFace> mFaceList = userFaceService.selectUserFaceList(userFace);
        int mFaceLen = mFaceList.size();
        if (mFaceLen > 0) {
            this.mFaceRegisterList.addAll(mFaceList);
        }
    }

    //人脸检测
    public List<ImageFeature> faceDetect(File file, FaceEngine faceEngine) {
        List<ImageFeature> imageFeatures = new ArrayList<>();
        try {
            // 获取图片信息
            ImageInfo imageInfo = ImageFactory.getRGBData(file);
            // 人脸检测
            List<FaceInfo> faceInfoList = new ArrayList<>();
            faceEngine.detectFaces(imageInfo, faceInfoList);
            if (faceInfoList.size() == 0) {
                //throw new ApiException(2102);
                // 帮助GC回收
                imageInfo = null;
                faceInfoList = null;
                throw new ArithmeticException("人脸图片不符合规定");
            }
            // 人脸属性检测
            faceEngine.process(imageInfo, faceInfoList, getFunctionConfiguration());
            // 口罩检测
            List<MaskInfo> maskInfoList = new ArrayList<>();
            faceEngine.getMask(maskInfoList);
            // 循环遍历
            for (int i = 0; i < faceInfoList.size(); i++) {
                ImageQuality imageQuality = new ImageQuality();
                faceEngine.imageQualityDetect(imageInfo, faceInfoList.get(i), maskInfoList.get(i).getMask(), imageQuality);
                float quality = imageQuality.getFaceQuality() - (maskInfoList.get(i).getMask() > 0 ? getMaskImageQuality() : getImageQuality());
                if (quality < 0) continue;
                //System.out.println("图片质量:" + imageQuality.getFaceQuality() + ",口罩:" + maskInfoList.get(i).getMask() + "");
                imageFeatures.add(ImageFeature.builder()
                        .imageInfo(imageInfo)
                        .faceInfo(faceInfoList.get(i))
                        .imageQuality(imageQuality)
                        .maskInfo(maskInfoList.get(i))
                        .build());
            }

            // 帮助GC回收
            imageInfo = null;
            faceInfoList = null;

            if (imageFeatures.size() == 0) {
                //throw new ApiException(2104);
                throw new ArithmeticException("人脸检测质量不通过");
            }
            // 返回图片特征集
        } catch (Exception e) {
            System.out.println("人脸检测错误:" + e.getMessage());
        }
        return imageFeatures;
    }

    // 特征提取
    public List<ImageFeature> faceExtract(File file, FaceEngine faceEngine) {
        List<ImageFeature> result = new ArrayList<>();
        try {
            List<ImageFeature> imageFeatures = faceDetect(file, faceEngine);
            if (imageFeatures == null || imageFeatures.size() == 0) {
                //throw new ApiException(2105);
                throw new ArithmeticException("人脸特征提取失败");
            }
            for (ImageFeature imageFeature : imageFeatures) {
                if (imageFeature.getImageInfo() == null || imageFeature.getFaceInfo() == null) {
                    continue;
                }
                FaceFeature faceFeature = new FaceFeature();
                faceEngine.extractFaceFeature(imageFeature.getImageInfo(), imageFeature.getFaceInfo(), ExtractType.REGISTER, imageFeature.getMaskInfo().getMask(), faceFeature);
                imageFeature.setFaceFeature(faceFeature);
                result.add(imageFeature);
            }
        } catch (Exception e) {
            System.out.println("特征提取错误:" + e.getMessage());
        }
        return result;
    }

    // 特征比对人脸
    public synchronized UserFace faceSearch(FaceFeature faceFeature, int isMask, boolean isRegister, FaceEngine mFaceEngine) {
        try {
            float maxSimilar = 0;
            float similarThreshold = getSimilarThreshold();
            if (isRegister) similarThreshold = getRegSimilarThreshold();
            UserFace userFace = null;
            for (UserFace itemFace : this.mFaceRegisterList) {
                FaceSimilar faceSimilar = new FaceSimilar();
                mFaceEngine.compareFaceFeature(faceFeature, new FaceFeature(itemFace.getFaceFeature()), faceSimilar);
                if (isRegister && faceSimilar.getScore() < similarThreshold) continue;
                if (faceSimilar.getScore() > maxSimilar) {
                    float similar = faceSimilar.getScore() - (isMask > 0 ? getMaskSimilarThreshold() : similarThreshold);
                    if (similar <= 0 || similar < maxSimilar) continue;
                    maxSimilar = similar;
                    userFace = itemFace;
                    userFace.setMask(isMask);
                    userFace.setSimilar(String.valueOf(faceSimilar.getScore()));
                }
            }
            return userFace;
        } catch (Exception e) {
            System.out.println("特征比对人脸:" + e.getMessage());
            return null;
        }
    }

    private FunctionConfiguration getFunctionConfiguration() {
        FunctionConfiguration configuration = new FunctionConfiguration();
        //configuration.setSupportAge(true);
        //configuration.setSupportGender(true);
        //configuration.setSupportLiveness(true);
        configuration.setSupportMaskDetect(true);
        return configuration;
    }

    /**
     * 获取人脸比对阀值
     *
     * @return
     */
    public float getSimilarThreshold() {
        // 判断是否使用配置
        if (enableFaceConfig) {
            FaceConfig faceConfig = getFaceConfig();
            if (faceConfig == null) return mSimilarThreshold;
            return Float.valueOf(faceConfig.getSimilarThreshold());
        } else {
            return mSimilarThreshold;
        }
    }

    /**
     * 获取人脸注册比对阀值
     *
     * @return
     */
    public float getRegSimilarThreshold() {
        // 判断是否使用配置
        if (enableFaceConfig) {
            FaceConfig faceConfig = getFaceConfig();
            if (faceConfig == null) return mRegSimilarThreshold;
            return Float.valueOf(faceConfig.getRegSimilarThreshold());
        } else {
            return mRegSimilarThreshold;
        }
    }

    /**
     * 获取戴口罩人脸注册比对阀值
     *
     * @return
     */
    public float getMaskSimilarThreshold() {
        // 判断是否使用配置
        if (enableFaceConfig) {
            FaceConfig faceConfig = getFaceConfig();
            if (faceConfig == null) return mMaskSimilarThreshold;
            return Float.valueOf(faceConfig.getMaskSimilarThreshold());
        } else {
            return mMaskSimilarThreshold;
        }
    }

    /**
     * 获取图片质量
     *
     * @return
     */
    public float getImageQuality() {
        // 判断是否使用配置
        if (enableFaceConfig) {
            FaceConfig faceConfig = getFaceConfig();
            if (faceConfig == null) return mImageQuality;
            return Float.valueOf(faceConfig.getImageQuality());
        } else {
            return mImageQuality;
        }
    }

    /**
     * 获取戴口罩的图片质量
     *
     * @return
     */
    public float getMaskImageQuality() {
        // 判断是否使用配置
        if (enableFaceConfig) {
            FaceConfig faceConfig = getFaceConfig();
            if (faceConfig == null) return mMaskImageQuality;
            return Float.valueOf(faceConfig.getMaskImageQuality());
        } else {
            return mMaskImageQuality;
        }
    }

    /**
     * 获取人脸配置
     *
     * @return
     */
    private FaceConfig getFaceConfig() {
        try {
            // 从 Redis 中获取存储的数据
            Object faceConfigObj = redisTemplate.opsForValue().get(FacePlusConstants.FACE_CONFIG);
            if (faceConfigObj == null) {
                // 查询数据库
                Long configId = Long.valueOf(1);
                FaceConfig faceConfig = faceConfigService.selectFaceConfigById(configId);
                if (faceConfig != null) {
                    // 创建 ObjectMapper 对象
                    ObjectMapper objectMapper = new ObjectMapper();
                    // 步骤 2：将实体对象转换为 JSON 字符串
                    String jsonString = objectMapper.writeValueAsString(faceConfig);
                    // 写入缓存
                    redisTemplate.opsForValue().set(FacePlusConstants.FACE_CONFIG, jsonString);
                }
                return faceConfig;
            } else {
                String faceConfigJson = (String) faceConfigObj;
                // 使用 Jackson 进行反序列化
                ObjectMapper objectMapper = new ObjectMapper();
                return objectMapper.readValue(faceConfigJson, FaceConfig.class);
            }
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            return null;
        }
    }
}
